package com.finance.cooperate.common.template;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;

/**
 * @ClassName RetryTemplate
 * @Description 代码重试模板类
 * @Author shen
 * @Date 2022/5/25 15:25
 * @Modify ...
 */
@Slf4j
public abstract class RetryTemplate {

    private static final int DEFAULT_RETRY_COUNT = 3;


    // 重试的睡眠时间
    private int sleepTime = 0;

    // 重试的次数
    private int retryCount = DEFAULT_RETRY_COUNT;

    // 结点信息
    private ProceedingJoinPoint joinPoint;


    public RetryTemplate setSleepTime(int sleepTime) {
        if(sleepTime < 0) {
            throw new IllegalArgumentException("sleepTime应该等于或大于0");
        }

        this.sleepTime = sleepTime;
        return this;
    }

    public RetryTemplate setRetryCount(int retryCount) {
        if (retryCount <= 0) {
            throw new IllegalArgumentException("retryCount应该大于0");
        }

        this.retryCount = retryCount;
        return this;
    }

    public RetryTemplate setJoinPoint(ProceedingJoinPoint joinPoint) {
        if(joinPoint == null) {
            throw new IllegalArgumentException("joinPoint不应该为null");
        }

        this.joinPoint = joinPoint;
        return this;
    }


    /**
     * @Author shen
     * @Description 重试的业务执行代码，失败时需要抛出异常，根据返回结果的状态来判定是否需要重试
     * @Date 4:3 下午 2020/11/6
     * @return Object
     **/
    protected abstract Object doBiz() throws Throwable;

    public Object execute() throws InterruptedException {

        Throwable finalException = null;

        for (int i = 0; i < retryCount; i++) {

            try {
                return doBiz();
            } catch (Throwable e) {
                log.warn("业务操作异常正在重试：" + i);
                finalException = e;
                Thread.sleep(sleepTime);
            }
        }

        // 重试 retryCount 次后抛出异常信息
        if (finalException != null) {

            log.error(
                    joinPoint.getSignature().getDeclaringType().getSimpleName() + "#"
                            + joinPoint.getSignature().getName() + " 出现异常，异常信息为：", finalException);
        }

        return null;
    }

    public Object submit(ExecutorService executorService) {
        if (executorService == null) {
            throw new IllegalArgumentException("请选择executorService！");
        }

        return executorService.submit((Callable) () -> execute());
    }

}
